package com.mrx.java8.lambda;

import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.function.Consumer;

/**
 * 一、Lambda表达式的基础语法： Java8中引入了一个新的操作符"->",该操作符成为箭头操作符或Lambda操作符
 *                         操作符将Lambda表达式分成两部分
 *
 * 左侧：Lambda 表达式的参数列表，对应接口中抽象方法的参数列表
 * 右侧：Lambda 表达式中所需要执行的功能，即 Lambda 体。对抽象方法的实现
 *
 * 语法格式一: 无参数,无返回值
 *  ()->System.out.println("Hello Lambda");
 *
 * 语法格式二: 一个参数,无返回值
 *  (x)->System.out.println(x);
 *
 * 语法格式三:若只有一个参数，小括号可以省略不写
 *   x->System.out.println(x);
 *
 * 语法格式四:有多个参数，有返回值，并且Lambda体中有多条语句
 *   Comparator<Integer> comparator = (x,y)->{
 *     System.out.println("Hello World");
 *     return Integer.compare(x,y);
 *   };
 *
 * 语法格式五: 若Lambda体中只有一条语句，return和大括号都可以省略不写
 *   Comparator<Integer> comparator = (x,y)-> Integer.compare(x,y);
 *
 * 语法格式六: Lambda表达式的参数列表的数据类型可以省略不写，因为JVM编译器通过上下文
 *           推断出参数类型，即：类型推断
 *
 * 总结：
 *  左右遇一括号省
 *      ：参数列表只有一个参数时()可以省，Lambda体只有一条语句时，{}可以省
 *  左侧推断类型省
 *      ：参数类型JVM可以进行类型推断，固参数类型可以省略
 *  能省则省
 *
 *
 * 二、Lambda表达式需要"函数式接口"的支持
 * 函数式接口：接口中只有一个抽象方法的接口，称为函数式接口。可使用注解@FunctionalInterface修饰
 *           注解课检查是否是函数式接口
 *
 *
 */
public class TestLambda2 {

    @Test
    public void test1(){
        // jdk1.7前，必须定义为final
        // jdk1.8中虽然可以省略final,但是实际上还是final
        int num = 0;
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World!"+num);
            }
        };
        r.run();

        System.out.println("------------------------------------");

        Runnable r1 = ()-> System.out.println("Hello Lambda"+num);
        r1.run();
    }


    @Test
    public void test2(){
        Consumer<String> consumer = (s) -> System.out.println(s);
        consumer.accept("Hello world");
    }

    @Test
    public void test3(){
        Consumer<String> consumer = s -> System.out.println(s);
        consumer.accept("Hello world");
    }


    @Test
    public void test4(){
        Comparator<Integer> comparator = (x,y)->{
            System.out.println("Hello World");
            return Integer.compare(x,y);
        };
        System.out.println(comparator.compare(1,2));
    }

    @Test
    public void test5(){
        Comparator<Integer> comparator = (x,y)-> Integer.compare(x,y);
        System.out.println(comparator.compare(3,1));
    }

    /** 原来关于类型推断的例子 */
    @Test
    public void test6(){
        // 可以推断
        String[] str = {"aaa","bbb","ccc"};

        /** 分开来写，无法完成推断 */
        String[] str2;
        //str2 = {"aaa","bbb","ccc"};

        /** 后面<>中不再需要些数据类型 */
        List<String> list = new ArrayList<>();

        /** JDK1.8中不需要指定参数，即可完成类型推断，JDK1.7中无法完成类型推断 */
        show(new HashMap<>());

    }

    public void show(Map<String,Integer> map){
        System.out.println("Hello Lambda");
    }


    // 需求: 对一个数进行运算
    @Test
    public void test7(){
        Integer num = operation(100,integer -> integer*integer);
        System.out.println(num);

        System.out.println(operation(100,integer -> integer+200));
    }

    public Integer operation(Integer num,MyFunction mf){
        return mf.getValue(num);
    }


}
